package com.jsftoolkit.gen;

import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

import com.jsftoolkit.gen.info.ClassInfo;
import com.jsftoolkit.gen.writer.ClassWriter;

/**
 * Pulls up some useful methods for all component class generators.
 * 
 * @author noah
 * 
 * @param <T>
 */
public abstract class AbstractComponentClassGenerator<T extends ClassWriter>
		implements ComponentClassGenerator<T> {

	/**
	 * Prints everything from the package declaration to the opening bracket.
	 * 
	 * @param writer
	 * @param info
	 * @param superClass
	 */
	protected void printToBody(ClassWriter writer, ClassInfo info,
			Class<?> superClass) {
		printPackageAndImports(writer, info, superClass);

		printDeclaration(writer, info, superClass);
	}

	/**
	 * Prints the class declaration (e.g. "public class Blah extends ... {").
	 * The only class modifiers this method will print are public and abstract.
	 * abstract is only printed if it is specified in the {@link ClassInfo}.
	 * <p>
	 * Also prints the class comment.
	 * 
	 * @param writer
	 * @param info
	 * @param superClass
	 */
	protected void printDeclaration(ClassWriter writer, ClassInfo info,
			Class<?> superClass) {
		int mods = Modifier.PUBLIC;
		if (info.isAbstract()) {
			mods |= Modifier.ABSTRACT;
		}

		writer.printClassComment();
		writer.printDeclaration(mods, info.getClassName(), superClass, info
				.getInterfaces());
	}

	/**
	 * Prints the class package declaration and the import statements. This
	 * method adds the super class and implemented interfaces to the set of
	 * imports.
	 * 
	 * @param writer
	 * @param info
	 * @param superClass
	 */
	protected void printPackageAndImports(ClassWriter writer, ClassInfo info,
			Class<?> superClass) {
		// package declaration
		writer.printPackage(info.getPackage());

		// import the interfaces and superclass
		Set<Class<?>> imports = new HashSet<Class<?>>(info.getImports());
		imports.addAll(info.getInterfaces());
		imports.add(superClass);

		writer.printImports(imports);
	}
}
